package site.cege;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.itextpdf.text.DocumentException;
import com.itextpdf.text.Element;
import com.itextpdf.text.Font;
import com.itextpdf.text.Phrase;
import com.itextpdf.text.pdf.PdfPCell;
import com.itextpdf.text.pdf.PdfPTable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import site.cege.config.CellConfig;

import java.io.IOException;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

public class PDFJSONUtil {
    static Logger logger = LoggerFactory.getLogger(PDFJSONUtil.class);

    public static PdfPTable buildTable(Font tableFont, String filePath, Map<String, Object> data) throws IOException, DocumentException {
        JSONObject pdfTableConfig = ParsePDFJSONUtil.parseJsonFile(filePath);
        JSONObject tableConfig = pdfTableConfig.getJSONObject("table");

        PdfPTable table =createTable(tableConfig);

        CellConfig cellConfig = ParsePDFJSONUtil.parseCellConfig(tableConfig);

        //获取列信息
        JSONArray columns = cellConfig.getColumns();

        //添加打印信息
        JSONObject printHeaderJson = tableConfig.getJSONObject("config").getJSONObject("printHeader");
        if(printHeaderJson.getBooleanValue("enabled")){
            CellConfig printHeaderConfig = ParsePDFJSONUtil.parseConfig(printHeaderJson);
            printHeaderConfig.setColspan(table.getNumberOfColumns());
            String fieldName = printHeaderJson.getString("operatorField");
            String info = "打印人：%s    打印时间：%s";
            String nowTime = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm"));
            info = String.format(info, Optional.ofNullable(data.get(fieldName)).orElse("张小三"), nowTime);
            PdfPCell headerCell = buildCell(info, tableFont, printHeaderConfig);
            table.addCell(headerCell);
        }
        //构建列信息与数据列
        JSONObject column;
        PdfPCell cell;
        int colspan = 0;
        for (Object ele : columns) {
            column = (JSONObject)ele;

            //信息列
            cell = buildCell(column.getString("name"), tableFont, cellConfig);
            table.addCell(cell);

            //数据列
            Object value = data.get(column.getString("field"));
            cell = buildCell(value, tableFont, cellConfig);

            colspan = column.getIntValue("colspan");
            if(colspan > 0){ cell.setColspan(colspan); }
            table.addCell(cell);
        }
        return table;
    }

    public static PdfPTable buildVerticalTable(Font tableFont, String filePath, List<Map<String, Object>> data, Map<String, Object> aggregateData) throws IOException, DocumentException {

        JSONObject pdfTableConfig = ParsePDFJSONUtil.parseJsonFile(filePath);
        JSONObject tableConfig = pdfTableConfig.getJSONObject("table");

        PdfPTable table = createTable(tableConfig);

        CellConfig cellConfig = ParsePDFJSONUtil.parseCellConfig(tableConfig);

        //获取列信息
        JSONArray columns = cellConfig.getColumns();

        //创建表格表头
        JSONObject column;
        PdfPCell cell;
        List<JSONObject> columnsList = new ArrayList<>();
        List<String> notRowspanColumnFieldNames = new ArrayList<>();
        for (Object ele : columns) {
            column = (JSONObject)ele;

            cell = buildCell(column.getString("name"), tableFont, cellConfig);
            table.addCell(cell);

            columnsList.add(column);
            if(!column.getBooleanValue("rowspan")){
                notRowspanColumnFieldNames.add(column.getString("field"));
            }
        }
        //添加数据
        int maxRowspan = 0;
        Object value;
        List listValue;
        for (Map<String, Object> dataElement : data) {
            maxRowspan = calculateMaxRowspan(dataElement, notRowspanColumnFieldNames);
            if(maxRowspan == 0){maxRowspan = 1;}
            for (int i = 0; i < maxRowspan; i++) { //一条数据需要maxRowspan行来支撑
                for(JSONObject jsonObject : columnsList){
                    //特殊对齐方式处理
                    specialConfig(jsonObject, cellConfig);

                    value = Optional.ofNullable(dataElement.get(jsonObject.getString("field"))).orElse(""); //每列的值
                    if(value instanceof List) {
                        listValue = (List)value;
                        if(i < listValue.size()){
                            value = Optional.ofNullable(listValue.get(i)).orElse("");
                            //对集合中的元素为对象的数据进行处理
                            if(Map.class.isAssignableFrom(value.getClass())){
                                value = ((Map)value).get(jsonObject.getString("innerField"));
                            }
                        }else{
                            value = "";
                        }
                    }

                    //第一行时数据都进行添加，如果大于一行则添加[rowspan]为false的列
                    if(i == 0){
                        cell = buildCell(value, tableFont, cellConfig);
                        if(jsonObject.getBoolean("rowspan")){ //每一条数据需要进行合并设置
                            cell.setRowspan(maxRowspan);
                        }
                        table.addCell(cell);
                    }else{
                       if(!jsonObject.getBoolean("rowspan")){
                           cell = buildCell(value, tableFont, cellConfig);
                           table.addCell(cell);
                       }
                    }
                }
            }
        }
        //合计信息
        table.getDefaultCell().setPhrase(new Phrase("", tableFont));
        addAggregateRow(tableConfig, table, aggregateData);

        return table;
    }

    public static String getClassPath(String fileName){
        return PDFJSONUtil.class.getClassLoader().getResource(fileName).getFile();
    }

    //添加合计行
    private static void addAggregateRow(JSONObject tableConfig, PdfPTable table, Map<String, Object> aggregateData) {
        JSONObject aggregateConfig = tableConfig.getJSONObject("aggregate");
        JSONArray columns = Optional.ofNullable(aggregateConfig.getJSONArray("columns")).orElse(new JSONArray());

        Font tableFont = table.getDefaultCell().getPhrase().getFont();
        CellConfig cellConfig = ParsePDFJSONUtil.parseConfig(aggregateConfig);

        JSONObject column;
        PdfPCell cell;
        Object value;
        String fieldName;
        for (Object element : columns) {
            column = (JSONObject)element;
            fieldName = column.getString("field");
            if(null == fieldName || "".equals(fieldName)){
                value = column.getString("name");
            }else{
                value = aggregateData.get(fieldName);
            }
            specialConfig(column, cellConfig);
            cell = buildCell(value, tableFont, cellConfig);
            table.addCell(cell);
        }
    }


    private static PdfPCell buildCell(Object content, Font tableFont, CellConfig cellConfig){
        content = Optional.ofNullable(content).orElse("");
        PdfPCell cell = new PdfPCell(new Phrase(content.toString(), tableFont));
        //添加样式
        cell.setBorder(cellConfig.getBorder());
        cell.setBorderColor(cellConfig.getBorderColor());
        cell.setFixedHeight(cellConfig.getColumnFixedHeight());
        cell.setVerticalAlignment(cellConfig.getVerticalAlignment());
        cell.setHorizontalAlignment(cellConfig.getHorizontalAlignment());
        cell.setColspan(cellConfig.getColspan());
        return cell;
    }

    //计算一条数据中最大合并行
    private static int calculateMaxRowspan(Map<String, Object> dataElement, List<String> notRowspanColumnFieldNames) {
        Object element;
        List<Object> value;
        List<Integer> rowspan = new ArrayList<>();
        for (String fieldName : notRowspanColumnFieldNames) {
            element = dataElement.get(fieldName);
            if(element instanceof List){
                value = (List)element;
                rowspan.add(value.size());
            }else{
                rowspan.add(0);
            }
        }
        return Collections.max(rowspan);
    }

    private static PdfPTable createTable(JSONObject table) throws DocumentException {
        JSONObject tableConfig = table.getJSONObject("config");
        //获取表格通用设置
        float[] widths = ParsePDFJSONUtil.getWidths(tableConfig);
        Integer initColumnNum = ParsePDFJSONUtil.getColumns(tableConfig);
        Float widthPercentage = ParsePDFJSONUtil.getWidthPercentage(tableConfig);
        Float spacingBefore = ParsePDFJSONUtil.getSpacingBefore(tableConfig);

        //构建Table
        PdfPTable pdfPTable = new PdfPTable(initColumnNum);
        if(widths.length > 0){
            pdfPTable.setWidths(widths);
        }
        pdfPTable.setWidthPercentage(widthPercentage);
        pdfPTable.setSpacingBefore(spacingBefore);
        return pdfPTable;
    }
    //转换为水平对齐方式
    private static int transAlign(String align){
        int result = Element.ALIGN_CENTER;
        align = Optional.ofNullable(align).orElse("");
        switch (align){
            case "center":
                result = Element.ALIGN_CENTER;
                break;
            case "left":
                result = Element.ALIGN_LEFT;
                break;
            case "right":
                result = Element.ALIGN_RIGHT;
                break;
            default:
                break;
        }
        return result;
    }

    private static void specialConfig(JSONObject column, CellConfig cellConfig){
        String align = column.getString("align");
        cellConfig.setHorizontalAlignment(transAlign(align));

        int colspan = column.getIntValue("colspan");
        cellConfig.setColspan(colspan);
    }
}
